考慮schema如下:
type User {
required name: str;
multi followers: User;
}
type Article {
required title: str;
required author: User;
}
本日的學習目標是希望透過前面幾天的說明,大家能獨自完成下面這四道練習:
Q1:建立三個User object,Jeff、Tom及Cathy,其name property分別為「"Jeff"」、「"Tom"」及「"Cathy"」。
Q2:將每個User object的multi followers link設定為除了自己以外的兩個User object。
Q3:將Cathy自每個User object的multi followers link中移除。
Q4:建立三個Article object,其title property分別為「"title1"」、「"title2"」、及「"title3"」,其author link為三個User object中隨機選取一位。
以下我們提供兩個方法作為參考答案。方法1是基礎的操作,而方法2借鑒方法1的寫法,並搭配for-loop使得query更加結構化。
insert User object首先建立三個User object,並指定其name property:
insert User {name:= "Jeff"};
insert User {name:= "Tom"};
insert User {name:="Cathy"};
此時三個User object成功建立。
select User {name};
{
default::User {name: 'Jeff'},
default::User {name: 'Tom'},
default::User {name: 'Cathy'}
}
update User object - 加入新User object至multi followers link接著update三個User object內的multi followers link:
update User filter .name="Jeff"
set {
multi followers:= (select User filter .name in {"Tom", "Cathy"})
};
update User filter .name="Tom"
set {
multi followers:= (select User filter .name in {"Jeff", "Cathy"})
};
update User filter .name="Cathy"
set {
multi followers:= (select User filter .name in {"Jeff", "Tom"})
};
但我們卻發現multi followers link並沒有更新,聰明的您看出來問題在哪邊了嗎?
select User {**};
{
default::User {
id: f789868a-4fd2-11ef-8734-db28a46e9f9c,
name: 'Jeff',
followers: {}
},
default::User {
id: f78ca9c8-4fd2-11ef-8734-53dcbb5a15d8,
name: 'Tom',
followers: {}
},
default::User {
id: f78ef002-4fd2-11ef-8734-eb9d204119a7,
name: 'Cathy',
followers: {}
},
}
沒錯,就是關於之前於[Day05]提過的detached,實務上這是一個非常容易犯錯的地方,需要多加小心。
正確的query可以寫為:
update User filter .name="Jeff"
set {
followers:= (select detached User filter .name in {"Tom", "Cathy"})
};
update User filter .name="Tom"
set {
followers:= (select detached User filter .name in {"Jeff", "Cathy"})
};
update User filter .name="Cathy"
set {
followers:= (select detached User filter .name in {"Jeff", "Tom"})
};
又或者搭配with寫為:
with jeff:= (select User filter .name="Jeff"),
followers:= (select User filter .name in {"Tom", "Cathy"})
update jeff
set {
followers:= followers
};
with tom:= (select User filter .name="tom"),
followers:= (select User filter .name in {"Jeff", "Cathy"})
update tom
set {
followers:= followers
};
with cathy:= (select User filter .name="Cathy"),
followers:= (select User filter .name in {"Jeff", "Tom"})
update cathy
set {
followers:= followers
};
update User object - 自multi followers link中移除Cathy這邊利用-=來移除Cathy:
with jeff:= (select User filter .name="Jeff"),
cathy:= (select User filter .name="Cathy")
update jeff
set {
followers-= cathy
};
with tom:= (select User filter .name="Tom"),
cathy:= (select User filter .name="Cathy")
update tom
set {
followers-= cathy
};
如果不習慣這樣的寫法,也可以寫成:
with jeff:= (select User filter .name="Jeff"),
cathy:= (select User filter .name="Cathy")
update jeff
set {
followers:= .followers except cathy
};
with tom:= (select User filter .name="Tom"),
cathy:= (select User filter .name="Cathy")
update tom
set {
followers:= .followers except cathy
};
留意這邊使用的是:=。:=代表將.followers except cathy這個set operation的結果指定給multi followers link。
insert Article object最後建立三個Article object,並指定其name property:
insert Article {
title:= "title1",
author:= (select User order by random() limit 1)
};
insert Article {
title:= "title2",
author:= (select User order by random() limit 1)
};
insert Article {
title:= "title3",
author:= (select User order by random() limit 1)
};
這邊我們使用了random()來隨機產生一個0.0 <= x < 1.0間的浮點數,並搭配order by來產生一個隨機的排序,最後再使用了limit 1來選擇第一個元素。
此時三個Article object成功建立。
select Article {title, author: {name} };
{
default::Article {title: 'title1', author: default::User {name: 'Cathy'}},
default::Article {title: 'title2', author: default::User {name: 'Cathy'}},
default::Article {title: 'title3', author: default::User {name: 'Tom'}},
}
insert User object我們將names集合為一個EdgeDBSet,就可以於迴圈中指定User object的name property。
with names:= {"Jeff", "Tom", "Cathy"}
for name in names
union (insert User {name:= name});
update User object - 加入新User object至multi followers link此處我們靈活運用set operation中的except來選取除自己外的User object。
with names:= {"Jeff", "Tom", "Cathy"}
for name in names
union (
with user:= (select User filter .name=name)
update user
set {
followers:= (select User except user)
}
);
update User object - 自multi followers link中移除Cathy這邊我們使用select User.name來選取所有User object的name property所形成的EdgeDBSet並使用except來排除「"Cathy"」這個str:
with names:= (select User.name except {"Cathy"}),
cathy:= (select User filter .name="Cathy")
for name in names
union (
with user:= (select User filter .name=name)
update user
set {
followers-= cathy
}
);
這種使用.來選擇object type的property或link十分方便,但初學時容易忘記,這邊特別提醒大家。
insert Article object此處我們利用range_unpack在每個迴圈中取得1, 2, 3,並使用<str>i將其轉為str型別後,搭配++與「"title"」合併。
for i in range_unpack(range(1, 4))
union (
insert Article {
title:= "title" ++ <str>i,
author:= (select User order by random() limit 1)
}
);